package com.ymx.darling.util;

import com.ymx.darling.exception.DarlingException;

import java.io.File;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

/**
 * 资源工具类
 * @author 爱Java的小于
 */
public class ResourceUtil {
    /**
     * 返回类路径下指定文件夹中所有的xml的文件名
     * @param resourcesDirectory 类路径下指定的资源目录
     * @return string[]
     */
    public static String[] getResourceXmlClasspath(String resourcesDirectory) {
        ClassLoader classLoader = getClassLoader();
        URL resource = classLoader.getResource(resourcesDirectory);
        if (resource == null) {
            throw new DarlingException("资源目录:"+resourcesDirectory+"不存在");
        }
        String resourcePath = resource.getPath();
        File resourceDir = new File(resourcePath);
        if (!resourceDir.isDirectory()) {
            throw new DarlingException(resourcesDirectory+"不是一个合法的资源目录");
        }

        String[] list = resourceDir.list();
        if (list != null) {
            for (int i = 0; i < list.length; i++) {
                list[i] = resourcesDirectory + "/" + list[i];
            }
        }
        return list;
    }


    /**
     * 获取类路径下指定包下的所有Class实例
     * @param packageName 包全限定名称
     * @return Class[]
     */
    public static List<Class<?>> getClassListByPackage(String packageName)  {
        // 检查包名路径是否存在
        ClassLoader classLoader = getClassLoader();
        URL resource = classLoader.getResource(packageName.replace('.', '/'));
        if (resource == null) {
            throw new DarlingException("包:"+packageName+"不存在");
        }
        String packagePath = resource.getPath();
        File packageDir = new File(packagePath);
        if (!packageDir.isDirectory()) {
            throw new DarlingException(packageName+"不是一个合法的包文件");
        }

        // 扫描指定包名下的所有类
        List<Class<?>> classList = new ArrayList<>();
        File[] files = packageDir.listFiles();
        if (files != null) {
            for (File file : files) {
                // 判断文件是一个包则递归读取内容
                if (file.isDirectory()) {
                    String childPackage = packageName + "." + file.getName();
                    List<Class<?>> classes = getClassListByPackage(childPackage);
                    classList.addAll(classes);
                }
                // 判断是以.class结尾
                if (file.getName().endsWith(".class")) {
                    String className = packageName + '.' + file.getName().substring(0, file.getName().length() - 6);
                    try {
                        Class<?> clazz = classForName(className);
                        // 排除类为内部类的情况
                        if (!clazz.isMemberClass()) {
                            classList.add(clazz);
                        }
                    } catch (ClassNotFoundException e) {
                        throw new DarlingException(e, "类加载异常:" + e);
                    }
                }
            }
        }

        return classList;
    }


    /**
     * 加载指定的类
     * @param className 类的全限定名称
     * @return Class
     * @throws ClassNotFoundException 无法加载此类或找不到时抛出此异常
     */
    public static Class<?> classForName(String className) throws ClassNotFoundException {
        ClassLoader classLoader = getClassLoader();
        try {
            return Class.forName(className, true, classLoader);
        } catch (ClassNotFoundException ignored) {}

        throw new ClassNotFoundException("找不到类型:" + className);
    }


    /**
     * 返回指定resource的InputStream流
     * @param resource 资源文件
     * @return InputStream
     */
    public static InputStream getResourceAsStream(String resource) {
        return getClassLoader().getResourceAsStream(resource);
    }


    /**
     * 按顺序返回类加载器<br/>
     * 1.当前线程类加载器
     * 2.ResourceUtil的类加载器
     * 3.系统类加载器
     * @return ClassLoader[]
     */
    public static ClassLoader getClassLoader() {
        ClassLoader currentThreadClassLoader = Thread.currentThread().getContextClassLoader();
        ClassLoader resourceUtilClassLoader = ResourceUtil.class.getClassLoader();
        ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
        if (currentThreadClassLoader != null) {
            return currentThreadClassLoader;
        } else if (resourceUtilClassLoader != null) {
            return resourceUtilClassLoader;
        } else {
            return systemClassLoader;
        }
    }
}